package lookie.app.ui.status;

import java.awt.Color;
import java.awt.Component;
import java.awt.SystemColor;

import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.UIManager;
import javax.swing.border.BevelBorder;
import javax.swing.border.Border;

import org.jdesktop.swingx.JXStatusBar;
import org.jdesktop.swingx.JXStatusBar.Constraint;
import org.springframework.richclient.application.statusbar.StatusBar;
import org.springframework.richclient.application.statusbar.support.StatusBarProgressMonitor;
import org.springframework.richclient.core.Message;
import org.springframework.richclient.factory.AbstractControlFactory;
import org.springframework.richclient.progress.ProgressMonitor;

public class LookieStatusBar extends AbstractControlFactory implements
		StatusBar {

	private String message;

	private String errorMessage;

	private JLabel messageLabel;

	private StatusBarProgressMonitor progressMonitor;

	private JXStatusBar statusBar;

	private MemoryStatus memoryStatus;

	/**
	 * Returns the status bar's progress monitor
	 */
	public ProgressMonitor getProgressMonitor() {
		return progressMonitor;
	}

	/**
	 * Controls whether the ProgressIndication provides UI for canceling a long
	 * running operation.
	 *
	 * If the ProgressIndication is currently visible calling this method may
	 * have a direct effect on the layout because it will make a cancel button
	 * visible.
	 */
	public void setCancelEnabled(boolean enabled) {
		progressMonitor.setCancelEnabled(enabled);
	}

	/**
	 * Sets the message text to be displayed on the status bar.
	 * <p>
	 * The icon of the message is ignored
	 *
	 * @param message
	 *            the message to be set, if <code>null</code>, the status line
	 *            is cleared.
	 */
	public void setMessage(Message message) {
		setMessage(message == null ? null : message.getMessage());
	}

	/**
	 * Sets the message text to be displayed on the status bar.
	 *
	 * @param message
	 *            the message to be set, if <code>null</code>, the status line
	 *            is cleared.
	 */
	public void setMessage(String message) {
		this.message = message;
		if (errorMessage == null) {
			logger.debug("Setting status bar message to \"" + message + "\"");
			messageLabel.setText(this.message);
		}
	}

	/**
	 * Sets the error message text to be displayed on the status bar.
	 * <p>
	 * Error messages are shown over the standard message, and in a red color.
	 * <p>
	 * The icon of the message is ignored
	 *
	 * @param message
	 *            the error message to be set, if <code>null</code>, the error
	 *            message is cleared, and the standard message is shown again
	 */
	public void setErrorMessage(Message errorMessage) {
		setErrorMessage(errorMessage == null ? null : errorMessage.getMessage());
	}

	/**
	 * Sets the error message text to be displayed on the status bar.
	 * <p>
	 * Error messages are shown over the standard message, and in a red color.
	 *
	 * @param message
	 *            the error message to be set, if <code>null</code>, the error
	 *            message is cleared, and the standard message is shown again
	 */
	public void setErrorMessage(String errorMessage) {
		if (errorMessage == null) {
			logger.debug("Resetting the status bar message color to normal");
			messageLabel.setForeground(SystemColor.controlText);

			this.errorMessage = null;
			setMessage(message);
		} else {
			logger.debug("Setting the status bar messsage color to red");
			messageLabel.setForeground(Color.RED);

			logger.debug("Setting status bar error message to \""
					+ errorMessage + "\"");
			this.errorMessage = errorMessage;
			messageLabel.setText(this.errorMessage);
		}
	}

	@Override
	protected JComponent createControl() {
		statusBar = new JXStatusBar();

		messageLabel = createMessageLabel();
		progressMonitor = createStatusBarProgressMonitor();
		memoryStatus = createMemoryStatus();

		Constraint c1 = new Constraint(
				JXStatusBar.Constraint.ResizeBehavior.FIXED);
		c1.setFixedWidth(200);
		statusBar.add(messageLabel, c1);
		Constraint c2 = new Constraint(
				JXStatusBar.Constraint.ResizeBehavior.FILL);
//		c2.setFixedWidth(200);
		statusBar.add(progressMonitor.getControl(), c2);

		Constraint c3 = new Constraint(
				JXStatusBar.Constraint.ResizeBehavior.FIXED);
		c3.setFixedWidth(100);
		statusBar.add(memoryStatus, c3);

		return statusBar;
	}

	/**
	 * Create the <code>JLabel</code> used to render the messages.
	 * <p>
	 * Can safely be overridden to customize the label
	 *
	 * @return the <code>JLabel</code>
	 */
	protected JLabel createMessageLabel() {
		JLabel messageLabel = new JLabel(" ");
		messageLabel.setName("message");
		Border bevelBorder = BorderFactory.createBevelBorder(
				BevelBorder.LOWERED, UIManager.getColor("controlHighlight"),
				UIManager.getColor("controlShadow"));
		Border emptyBorder = BorderFactory.createEmptyBorder(1, 3, 1, 3);
		messageLabel.setBorder(BorderFactory.createCompoundBorder(bevelBorder,
				emptyBorder));

		return messageLabel;
	}

	/**
	 * Create the <code>StatusBarProgressMonitor</code>.
	 * <p>
	 * Can safely be overridden to customize the progress monitor and its
	 * components
	 *
	 * @return the <code>StatusBarProgressMonitor</code>
	 */
	protected StatusBarProgressMonitor createStatusBarProgressMonitor() {
		return new StatusBarProgressMonitor();
	}

	protected MemoryStatus createMemoryStatus() {
		MemoryStatus memoryStatus = new MemoryStatus();

		Border bevelBorder = BorderFactory.createBevelBorder(
				BevelBorder.LOWERED, UIManager.getColor("controlHighlight"),
				UIManager.getColor("controlShadow"));
		Border emptyBorder = BorderFactory.createEmptyBorder(1, 3, 1, 3);
		memoryStatus.setBorder(BorderFactory.createCompoundBorder(bevelBorder,
				emptyBorder));

		return memoryStatus;
	}

	public void clear() {
		setErrorMessage((String) null);
		setMessage((String) null);
	}

	/**
	 * Shows or hides this status bar.
	 *
	 * @see Component#setVisible(boolean)
	 */
	public void setVisible(boolean visible) {
		statusBar.setVisible(visible);
	}

}
